package top.xia17.plugins.fast.common.database.mybatis.query;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;
import top.xia17.plugins.fast.common.model.BiObjSortKey;
import top.xia17.plugins.fast.common.utils.ObjUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * mybatis 查询帮助
 * @author xia17
 * @date 2021/2/3 9:48
 */
public class IQueryHelp {

    /** 是否需要驼峰转下划线 */
    private static boolean NEED_TO_UNDERLINE_CASE = true;

    /**
     * 设置 是否需要驼峰转下划线
     * @param b true 需要
     */
    public static void setNeedCast(boolean b){
        NEED_TO_UNDERLINE_CASE = b;
    }


    /**
     * 生成查询条件
     * @param query /
     * @param <T> /
     * @return /
     */
    public static<Q,T> QueryWrapper<T> toQueryWrapper(Q query)  {
        QueryWrapper<T> wrapper = Wrappers.query();
        List<Field> fields = ObjUtil.getAllFields(query.getClass());
        List<BiObjSortKey<String,Boolean>> sorts = new ArrayList<>();
        String  columns , column;
        for (Field field : fields) {
            boolean accessible = field.isAccessible();
            // 设置对象的访问权限，保证对private的属性的访
            field.setAccessible(true);
            IQuery q = field.getAnnotation(IQuery.class);
            if (q == null){
                continue;
            }
            Object val;
            try {
                 val = field.get(query);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                throw new BadRequestException("mybatis的动态查询生成失败",e);
            }
            // 如果属性为NULL 或者空字符串 则 不添加查询条件
            if (ObjectUtil.isNull(val) || "".equals(val)) {
                continue;
            }
            columns = q.columns();
            column = getColumn(q,field);
            // 多字段查询 中间使用or相连
            if (StrUtil.isNotEmpty(columns)){
                String[] blurryArray = columns.split(",");
                if (blurryArray.length < 2){
                    throw new BadRequestException("IQueryError , 使用多字段查询时请至少使用两个字段");
                }
                wrapper.and(queryWrapper -> {
                    for (int i = 0; i < blurryArray.length; i++) {
                        // 添加一个查询
                        addQuery(queryWrapper,q,blurryArray[i], val,sorts);
                        if (i != blurryArray.length - 1){
                            // 如果不是最后一行 加上or条件
                            queryWrapper.or();
                        }
                    }
                });
                continue;
            }
            // 添加一个查询
            addQuery(wrapper,q,column, val,sorts);
            field.setAccessible(accessible);
        }
        addSort(wrapper,sorts);
        return wrapper;
    }

    /**
     * 获取column
     * @param q 注解
     * @param field 字段
     * @return /
     */
    private static String getColumn(IQuery q , Field field){
        String column = q.column();
        if (!StrUtil.isEmpty(column)){
            return column;
        }
        return NEED_TO_UNDERLINE_CASE ? StrUtil.toUnderlineCase(field.getName()) : field.getName();
    }

    /**
     * 添加一个查询条件
     * @param queryWrapper 查询包装器
     * @param query 查询条件
     * @param column 字段名
     * @param val 值
     * @param <T> /
     */
    private static<T> void addQuery(QueryWrapper<T> queryWrapper , IQuery query , String column , Object val , List<BiObjSortKey<String,Boolean>> sorts){
        Collection<?> collection;
        Object[] objects;
        IQuery.Type type = query.type();
        switch (type) {
            case EQ:
                queryWrapper.eq(column,val);
                break;
            case NE:
                queryWrapper.ne(column,val);
                break;
            case GT:
                queryWrapper.gt(column,val);
                break;
            case GE:
                queryWrapper.ge(column,val);
                break;
            case LT:
                queryWrapper.lt(column,val);
                break;
            case LE:
                queryWrapper.le(column,val);
                break;
            case INNER_LIKE:
                queryWrapper.like(column,val);
                break;
            case LEFT_LIKE:
                queryWrapper.likeLeft(column,val);
                break;
            case RIGHT_LIKE:
                queryWrapper.likeRight(column,val);
                break;
            case IN:
                collection = (Collection<?>) val;
                if (CollUtil.isNotEmpty(collection)) {
                    queryWrapper.in(column,collection);
                }
                break;
            case NOT_IN:
                collection = (Collection<?>) val;
                if (CollUtil.isNotEmpty(collection)) {
                    queryWrapper.notIn(column,collection);
                }
                break;
            case NOT_NULL:
                queryWrapper.isNotNull(column);
                break;
            case IS_NULL:
                queryWrapper.isNull(column);
                break;
            case BETWEEN:
                collection = (Collection<?>) val;
                objects = collection.toArray();
                queryWrapper.between(column,objects[0],objects[1]);
                break;
            case NOT_BETWEEN:
                collection = (Collection<?>) val;
                objects = collection.toArray();
                queryWrapper.notBetween(column,objects[0],objects[1]);
                break;
            case ORDER:
                sorts.add(new BiObjSortKey<>(query.sort(),column,(boolean) val));
                break;
            case ASC:
                if ((boolean) val){
                    sorts.add(new BiObjSortKey<>(query.sort(),column,true));
                }
                break;
            case DESC:
                if ((boolean) val){
                    sorts.add(new BiObjSortKey<>(query.sort(),column,false));
                }
                break;
            default: break;
        }
    }

    /**
     * 添加排序
     * @param queryWrapper 查询包装器
     * @param sorts 排序条件
     */
    private static<T> void addSort(QueryWrapper<T> queryWrapper , List<BiObjSortKey<String,Boolean>> sorts){
        // 排序
        sorts.sort(BiObjSortKey::compareTo);
        // 遍历添加 order条件
        for (BiObjSortKey<String, Boolean> sort : sorts) {
            queryWrapper.orderBy(true,sort.getData(),sort.getValue());
        }
    }



}
